package com.hqyj.javaSpringBoot.modules.test.service.impl;

import com.hqyj.javaSpringBoot.modules.common.entiy.ResultEntity;
import com.hqyj.javaSpringBoot.modules.common.entiy.SearchBean;
import com.hqyj.javaSpringBoot.modules.test.entity.Student;
import com.hqyj.javaSpringBoot.modules.test.repository.StudentRepository;
import com.hqyj.javaSpringBoot.modules.test.service.StudentService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.time.LocalDateTime;

@Service
public class StudentServiceImpl implements StudentService {

    @Autowired
    private StudentRepository studentRepository;

    @Override
    @Transactional
    public ResultEntity<Student> insertStudent(Student student) {
        studentRepository.saveAndFlush(student);
        return new ResultEntity<>(ResultEntity.ResultStatus.SUCCESS.code,"insert success",student);
    }

    @Override
    @Transactional
    public ResultEntity<Student> deleteStudent(int id) {
        studentRepository.deleteById(id);
        return new ResultEntity<>(ResultEntity.ResultStatus.SUCCESS.code,"delete success");
    }

    @Override
    @Transactional
    public ResultEntity<Student> updateStudent(Student student) {
        studentRepository.saveAndFlush(student);
        return new ResultEntity<>(ResultEntity.ResultStatus.SUCCESS.code,"update success");
    }

    @Override
    public Student getStudentById(int id) {
        return studentRepository.findById(id).get();
    }

    @Override
    public Student getStudentNameAndAge(String studentName, Integer age) {
        return studentRepository.findFirstByStudentNameAndAge(studentName,age);
    }

    @Override
    public Page<Student> getStudentBySearch(SearchBean searchBean) {
//        return exampleBySearch(searchBean);
        return criteriaBySearch(searchBean);
    }

    @Override
    public Student getStudentByIdV2(int id) {
        return studentRepository.getStudentByIdV2(id);
    }

    @Override
    @Transactional
    public ResultEntity<Student> updateStudentNameById(Student student) {
        studentRepository.updateStudentNameById(student.getStudentName(),student.getId());
        return new ResultEntity<>(ResultEntity.ResultStatus.SUCCESS.code,"update success",student);
    }

    /**Example + Page 查询*/
    public Page<Student> exampleBySearch(SearchBean searchBean){
        searchBean.initSerchBean();
        /**
         * 排序的方向，进行非空asc判断
         * 创建sort排序对象
         * new Sort(direction, orderBy)；
         * direction：排序方向，Sort.Direction.ASC；
         * orderBy：排序字段；
         */
        Sort.Direction direction=StringUtils.isBlank(searchBean.getDirection())||searchBean.getDirection().
                equalsIgnoreCase("asc")? Sort.Direction.ASC:Sort.Direction.DESC;
        String orderBy = StringUtils.isBlank(searchBean.getOrderBy())?"id":searchBean.getOrderBy();
        Sort sort=Sort.by(direction,orderBy);

        /**
         *Pageable：分页组件
         * 默认page为0开始
         * public static PageRequest of(int page, int size, Sort sort)；
         */
        PageRequest pageRequest=PageRequest.of(searchBean.getCurrentPage()-1,
                searchBean.getPageSize(),sort);

        Student student=new Student();
        student.setStudentName(searchBean.getKeyWord());
        /**
         * 创建ExampleMatcher匹配器，即如何使用查询条件
         * withMatcher("studentName",matcher->matcher.contains())
         *          学生姓名采用了模糊查询，即 %studentName%；
         * withIgnorePaths("id", "age")
         *          忽略属性，是否关注，因为是基本数据类型，存在默认值，所以需要忽略
         * */
        ExampleMatcher  exampleMatcher=ExampleMatcher.matching().
                withMatcher("studentName",matcher->matcher.contains()).withIgnorePaths("id", "age");
        Example<Student> example=Example.of(student,exampleMatcher);
        return studentRepository.findAll(example,pageRequest);
    }

    /**
     * Criteria + Page
     * Criteria 多条件查询，支持时间比较、数字比较等
     * select * from test_student where createDate>=?
     * and (studentName like ? or id between 10 and 20) order by id desc limit ?
     *
     */
    public Page<Student> criteriaBySearch(SearchBean searchBean){
        searchBean.initSerchBean();
        Sort.Direction direction=StringUtils.isBlank(searchBean.getDirection())||searchBean.getDirection().
                equalsIgnoreCase("asc")? Sort.Direction.ASC:Sort.Direction.DESC;
        String orderBy = StringUtils.isBlank(searchBean.getOrderBy())?"id":searchBean.getOrderBy();
        Sort sort=Sort.by(direction,orderBy);
        PageRequest pageRequest=PageRequest.of(searchBean.getCurrentPage()-1,
                searchBean.getPageSize(),sort);

        /**
         * Root是查询结果的一个实体对象，也就是查询结果返回的主要对象
         * CriteriaQuery<T>，这个是JPA标准，主要是构建查询条件的，
         *      里面的方法都是各种查询方式：distinct、select、where、groupby、having、orderby这些方法
         * CriteriaBuilder，这个接口主要是用来进行一些函数操作，主要做条件拼接
         */
        Specification<Student> specification=new Specification<Student>() {
            @Override
            public Predicate toPredicate(Root<Student> root, CriteriaQuery<?>
                    criteriaQuery, CriteriaBuilder criteriaBuilder) {
                return criteriaBuilder.and(
                        criteriaBuilder.greaterThanOrEqualTo(
                                root.get("createDate").as(LocalDateTime.class),
                                LocalDateTime.of(2020,12,12,0,0,0)
                        ),
                        criteriaBuilder.or(
                                criteriaBuilder.like(
                                        root.get("studentName").as(String.class),
                                        String.format("%%%s%%",searchBean.getKeyWord())
                                ),
                                criteriaBuilder.between(root.get("id").as(Integer.class),1,20)
                        )
                );
            }
        };
        return studentRepository.findAll(specification,pageRequest);
    }



}

